package org.wattdepot.gdata.kukuicup.service;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import com.google.gdata.data.spreadsheet.Cell;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.CellEntry;


/**
 * Implements a read-only view of a spreadsheet.
 * @author Philip Johnson
 *
 */
public class GDataView {
  
  /** The contents of the spreadsheet. */
  private List<CellEntry> entries;

  /**
   * Creates a GDataView instance, and reads the current contents of the passed URL.
   * @param gdata The GData service.
   * @param spreadsheetURL The URL of the spreadsheet to retrieve.
   * @throws Exception If problems occur reading the data from the spreadsheet.
   */
  public GDataView(GDataService gdata, URL spreadsheetURL) throws Exception {
    CellFeed feed = gdata.getSpreadsheetService().getFeed(spreadsheetURL, CellFeed.class);
    this.entries = feed.getEntries();
  }
  
  /**
   * Returns a list of Cell instances associated with the passed row.
   * @param row The row of interest.
   * @return The cells in that row, in column order.
   */
  public List<Cell> getRow(int row) {
    List<Cell> cells = new ArrayList<Cell>();
    for (CellEntry entry : this.entries) {
      Cell cell = entry.getCell();
      // Cells are stored in row-major order, so we can return now if we're past that row.
      if (cell.getRow() > row) {
        return cells;
      }
      // Otherwise add the cell if it's the correct row.
      if (cell.getRow() == row) {
        cells.add(cell);
      }
    }
    return cells;
  }
  
  /**
   * Returns a list of Cell instances associated with the passed column.
   * @param column The column of interest.
   * @return The cells in that column, in row order.
   */
  public List<Cell> getColumn(int column) {
    List<Cell> cells = new ArrayList<Cell>();
    for (CellEntry entry : this.entries) {
      Cell cell = entry.getCell();
      if (cell.getCol() == column) {
        cells.add(cell);
      }
    }
    return cells;
  }
  
  /**
   * Returns a list of the values corresponding to the passed cells.
   * @param cells The cells of interest.
   * @return A list of their values. 
   */
  public List<String> getCellData(List<Cell> cells) {
    List<String> cellData = new ArrayList<String>();
    for (Cell cell : cells) {
      cellData.add(cell.getValue());
    }
    return cellData;
  }
  
  /**
   * Returns the cell at (row, column), or null if not found. 
   * @param row The row.
   * @param column The column.
   * @return The cell at (row, column), or null.
   */
  public Cell findCell(int row, int column) {
    for (CellEntry entry : this.entries) {
      Cell cell = entry.getCell();
      if ((cell.getRow() == row) && (cell.getCol() == column)) {
        return cell;
      } 
      else if (cell.getRow() > row) {
        return null;
      }
    }
    return null;
  }

  /**
   * Returns the row associated with the first cell found with the passed value.
   * @param value The value to be searched for.
   * @return The row associated with this value.
   * @throws RuntimeException If no cell with this value can be found.
   */
  public int findRow(String value) {
    for (CellEntry entry : this.entries) {
      Cell cell = entry.getCell();
      if (value.equals(cell.getValue())) {
        return cell.getRow();
      }
    }
    throw new RuntimeException("Could not find a cell with contents: " + value);
  }
  
  /**
   * Returns a string representing the contents of the cell at (row, column).  
   * If there is no cell data at that position, then returns the empty string. 
   * @param row The row of interest.
   * @param column The cell of interest.
   * @return The string representing the cell contents, or the empty string.
   */
  public String getCellData(int row, int column) {
    Cell cell = findCell(row, column);
    return (cell == null) ? "" : cell.getValue();
  }

  
  /**
   * Returns the number of cells in the spreadsheet.
   * @return The number of cells in the spreadsheet.
   */
  public int size() {
    return this.entries.size();
  } 
  
  /**
   * Debugging method that prints out the contents of the entire spreadsheet.
   */
  public void printCells() {
    for (CellEntry entry : this.entries) {
      Cell cell = entry.getCell();
      System.out.format("(%s, %s) %s%n", cell.getRow(), cell.getCol(), cell.getValue());
    }
  }

}
